"""
@File         : service.py
@Time         : 2024/05/09 16:21:46
@Author       : Qrj
@Email        : 923207736@qq.com
@Description  : 站内信模板相关业务逻辑
"""


from cashews import NOT_NONE
from sqlalchemy import and_, delete, func, insert, select, update
from sqlalchemy.ext.asyncio import AsyncSession

from src.exceptions.custom_async_validator import generate_async_validator_exception
from src.schemas.validate import (
    OrderBySearchValidateSchema,
    PaginationSearchValidateSchema,
)
from src.utils.cashews import CashewsCondition, data_cache
from src.utils.string import StringReplaceUtil

from .models import StationMessageTemplate
from .schemas.out import (
    ListStationMessageTemplateCompleteOutSchema,
    StationMessageTemplateCompleteOutSchema,
)
from .schemas.validate import (
    StationMessageTemplateCreateValidateSchema,
    StationMessageTemplateDeleteValidateSchema,
    StationMessageTemplateListSearchValidateSchema,
    StationMessageTemplateUpdateStatusValidateSchema,
    StationMessageTemplateUpdateValidateSchema,
)


class StationMessageTemplateService:
    """站内信模板业务逻辑类"""

    @data_cache(
        ttl="30m",
        key="station_message_template#id:{station_message_template_id}",
        tags=[
            "station_message_template#id",
            "station_message_template#id:{station_message_template_id}",
        ],
        condition=NOT_NONE,
    )
    @staticmethod
    async def get_station_message_template_use_id(
        db_session: AsyncSession,
        station_message_template_id: int,
        raise_not_exists_exception: bool = True,
        raise_disabled_exception: bool = True,
    ) -> StationMessageTemplateCompleteOutSchema | None:
        """通过主键获取站内信模板信息实例

        Args:
            db_session (AsyncSession): 数据库连接池
            station_message_template_id (int): 站内信模板ID
            raise_not_exists_exception (bool, optional): 没找到的话是否直接报错
            raise_disable_exception (bool, optional): 禁用的话是否直接报错

        Returns:
            StationMessageTemplateCompleteOutSchema | None: 站内信模板实例
        """
        search_sql = select(
            *StationMessageTemplateCompleteOutSchema.convert_to_sql_model_field(
                StationMessageTemplate
            )
        ).where(
            StationMessageTemplate.id == station_message_template_id,
        )
        async with db_session.begin():
            search_res = await db_session.execute(search_sql)
        result = search_res.mappings().first()
        if result is not None:
            result = StationMessageTemplateCompleteOutSchema.model_validate(result)
            if (not result.status) and raise_disabled_exception:
                # 禁用则报错
                raise generate_async_validator_exception("id", "站内信模板已被禁用")
            return result
        elif result is None and raise_not_exists_exception:
            # 未找到则报错
            raise generate_async_validator_exception("id", "站内信模板不存在")
        else:
            return result

    @data_cache(
        ttl="30m",
        key="station_message_template#name:{station_message_template_name}",
        tags=[
            "station_message_template#name",
            "station_message_template#name:{station_message_template_name}",
        ],
        condition=NOT_NONE,
    )
    @staticmethod
    async def get_station_message_template_use_name(
        db_session: AsyncSession,
        station_message_template_name: str,
        raise_not_exists_exception: bool = True,
        raise_disabled_exception: bool = True,
    ) -> StationMessageTemplateCompleteOutSchema | None:
        """通过主键获取站内信模板信息实例

        Args:
            db_session (AsyncSession): 数据库连接池
            station_message_template_name (str): 站内信模板名称
            raise_not_exists_exception (bool, optional): 没找到的话是否直接报错
            raise_disable_exception (bool, optional): 禁用的话是否直接报错

        Returns:
            StationMessageTemplateCompleteOutSchema | None: 站内信模板实例
        """
        search_sql = select(
            *StationMessageTemplateCompleteOutSchema.convert_to_sql_model_field(
                StationMessageTemplate
            )
        ).where(
            StationMessageTemplate.name == station_message_template_name,
        )
        async with db_session.begin():
            search_res = await db_session.execute(search_sql)
        result = search_res.mappings().first()
        if result is not None:
            result = StationMessageTemplateCompleteOutSchema.model_validate(result)
            if (not result.status) and raise_disabled_exception:
                # 禁用则报错
                raise generate_async_validator_exception("id", "站内信模板已被禁用")
            return result
        elif result is None and raise_not_exists_exception:
            # 未找到则报错
            raise generate_async_validator_exception("id", "站内信模板不存在")
        else:
            return result

    @data_cache(
        ttl="30m",
        key="station_message_template_list:{search_schema}:{pagination_schema}:{order_schema}",
        tags=["station_message_template_list"],
        condition=CashewsCondition.condition_only_true_result,
    )
    @staticmethod
    async def list_search_station_message_template(
        db_session: AsyncSession,
        search_schema: StationMessageTemplateListSearchValidateSchema,
        pagination_schema: PaginationSearchValidateSchema,
        order_schema: OrderBySearchValidateSchema,
        need_select_total: bool = True,
    ) -> tuple[list[StationMessageTemplateCompleteOutSchema], int | None]:
        """无公告内容的站内信模板列表查询

        Args:
            db_session (AsyncSession): 数据库连接池
            search_schema (StationMessageTemplateListSearchValidateSchema): 查询参数
            pagination_schema: 分页参数
            order_schema: 排序参数
            need_select_total: 是否需要查询总数

        Returns:
            tuple[list[StationMessageTemplateCompleteOutSchema], int | None]: 查询结果、查询总数
        """
        # 构建排序字段
        order_by_field_sql = order_schema.convert_to_order_by_sql(
            search_schema, StationMessageTemplate
        )
        # 构建查询sql
        list_search_sql = (
            select(
                *StationMessageTemplateCompleteOutSchema.convert_to_sql_model_field(
                    StationMessageTemplate
                )
            )
            .where(
                and_(*search_schema.convert_to_where_sql(StationMessageTemplate)),
            )
            .order_by(order_by_field_sql)
            .offset(pagination_schema.offset)
            .limit(pagination_schema.limit)
        )
        # 开始查询
        async with db_session.begin():
            list_search_res = await db_session.execute(list_search_sql)
        result = list_search_res.mappings().all()
        # 根据need_select_total参数来确定是否需要查询总数
        if need_select_total:
            total_sql = (
                select(func.count())
                .select_from(StationMessageTemplate)
                .where(
                    and_(*search_schema.convert_to_where_sql(StationMessageTemplate)),
                )
            )
            async with db_session.begin():
                total_res = await db_session.execute(total_sql)
            total = total_res.scalar()
        else:
            total = None
        # 统一转为pydantic列表模型
        return ListStationMessageTemplateCompleteOutSchema.validate_python(
            result
        ), total

    @staticmethod
    async def create_station_message_template(
        db_session: AsyncSession,
        create_schema: StationMessageTemplateCreateValidateSchema,
        creator_username: str = "",
        is_init: bool = False,
    ) -> int:
        """创建站内信模板

        Args:
            db_session (AsyncSession): 数据库连接池
            create_schema (StationMessageTemplateCreateValidateSchema): 创建所需的信息
            creator_username (str, optional): 创建者用户名
            is_init (bool): 是否初始模板

        Returns:
            int: 创建的sql的主键ID
        """
        # 构建创建信息字典
        create_info_dict = create_schema.model_dump()
        # 构建模板参数
        template_params = StringReplaceUtil.get_string_var(create_schema.content)
        # 创建
        create_sql = insert(StationMessageTemplate).values(
            creator_username=creator_username,
            is_init=is_init,
            params=template_params,
            **create_info_dict,
        )
        async with db_session.begin():
            create_res = await db_session.execute(create_sql)
            # 清空相关缓存标签
            await data_cache.delete_tags("station_message_template_list")
        return create_res.inserted_primary_key_rows[0][0]

    @staticmethod
    @data_cache.transaction()
    async def update_station_message_template(
        db_session: AsyncSession,
        update_schema: StationMessageTemplateUpdateValidateSchema,
        updater_username: str = "",
    ):
        """修改站内信模板信息

        Args:
            db_session (AsyncSession): 数据库连接池
            update_schema (StationMessageTemplateUpdateValidateSchema): 修改操作所需的数据
            updater_username (str, optional):修改者用户名
        """
        # 检查需修改的sql实例是否存在(禁用不报错)
        update_obj: StationMessageTemplateCompleteOutSchema = (
            await StationMessageTemplateService.get_station_message_template_use_id(
                db_session,
                update_schema.id,
                raise_disabled_exception=False,
                raise_expired_exception=False,
            )
        )
        # 不允许修改初始站内信模板
        if update_obj.is_init:
            raise generate_async_validator_exception("id", "不能修改初始站内信模板")
        # 构建修改所需的数据(排除未设置的值和id)
        update_schema_data = update_schema.model_dump(
            exclude=("id",), exclude_unset=True
        )
        # 构建模板参数
        template_params = StringReplaceUtil.get_string_var(update_schema.content)
        if update_schema_data:
            # 修改sql
            update_sql = (
                update(StationMessageTemplate)
                .values(
                    **update_schema_data,
                    updater_username=updater_username,
                    params=template_params,
                )
                .where(
                    StationMessageTemplate.id == update_schema.id,
                )
            )
            # 修改操作
            async with db_session.begin():
                # 修改sql数据
                await db_session.execute(update_sql)
                # 清空相关缓存标签
                await data_cache.delete_tags(
                    f"station_message_template#id:{update_schema.id}",
                    f"station_message_template#name:{update_obj.name}",  # 旧名称的相关缓存
                    "station_message_template_list",
                )

    @staticmethod
    @data_cache.transaction()
    async def update_station_message_template_status(
        db_session: AsyncSession,
        update_schema: StationMessageTemplateUpdateStatusValidateSchema,
        updater_username: str = "",
    ):
        """单独修改站内信模板状态

        Args:
            db_session (AsyncSession): 数据库连接池
            tenant_id (int): 租户ID
            update_schema (StationMessageTemplateUpdateStatusValidateSchema): 修改操作所需的数据
            updater_username (str, optional):修改者用户名
        """
        # 检查需修改的sql实例是否存在(禁用不报错)
        update_obj: StationMessageTemplateCompleteOutSchema = (
            await StationMessageTemplateService.get_station_message_template_use_id(
                db_session,
                update_schema.id,
                raise_disabled_exception=False,
                raise_expired_exception=False,
            )
        )
        # 不允许修改初始站内信模板
        if update_obj.is_init:
            raise generate_async_validator_exception("id", "不能修改初始站内信模板")
        # 修改sql
        update_sql = (
            update(StationMessageTemplate)
            .values(status=update_schema.status, updater_username=updater_username)
            .where(
                StationMessageTemplate.id == update_schema.id,
            )
        )
        # 修改操作
        async with db_session.begin():
            # 修改sql数据
            await db_session.execute(update_sql)
            # 清空相关缓存标签
            await data_cache.delete_tags(
                f"station_message_template#id:{update_schema.id}",
                f"station_message_template#name:{update_obj.name}",  # 旧名称的相关缓存
                "station_message_template_list",
            )

    @staticmethod
    @data_cache.transaction()
    async def delete_station_message_template(
        db_session: AsyncSession,
        delete_schema: StationMessageTemplateDeleteValidateSchema,
    ):
        """删除站内信模板

        Args:
            db_session (AsyncSession): 数据库连接池
            delete_schema (StationMessageTemplateDeleteValidateSchema): 删除操作所属的数据
        """
        # 查找需删除的实例
        # 构建查询sql
        select_sql = select(
            StationMessageTemplate.id,
            StationMessageTemplate.name,
            StationMessageTemplate.is_init,
        ).where(StationMessageTemplate.id.in_(delete_schema.ids))
        # 进行sql查询
        async with db_session.begin():
            select_res = await db_session.execute(select_sql)
        select_result = select_res.mappings().all()
        # 检查是否删除了初始的站内信模板
        if any([i["is_init"] for i in select_result]):
            raise generate_async_validator_exception("ids", "不允许删除初始站内信模板")

        # 进行删除操作
        if select_result:
            # 获取需要删除的用户id列表
            delete_id_list = [i["id"] for i in select_result]
            # 获取需要删除的用户名列表
            delete_name_list = [i["name"] for i in select_result]
            # 删除用户本身的sql
            delete_sql = delete(StationMessageTemplate).where(
                StationMessageTemplate.id.in_(delete_id_list)
            )
            # 删除操作
            async with db_session.begin():
                # 删除sql中的数据
                await db_session.execute(delete_sql)
                # 清空相关缓存标签
                delete_cache_tags = [
                    *[f"station_message_template#id:{i}" for i in delete_id_list],
                    *[
                        f"station_message_template#name:{i}" for i in delete_name_list
                    ],  # 旧名称的相关缓存
                    "station_message_template_list",
                ]
                # 清空相关缓存标签
                await data_cache.delete_tags(*delete_cache_tags)
